package com.moonshineproject.plugin.actionscript.as3parser.completers
{
	import __AS3__.vec.Vector;
	
	import com.moonshineproject.plugin.actionscript.as3parser.MetadataManager;
	import com.moonshineproject.plugin.actionscript.as3parser.parsers.ImportParser;
	import com.moonshineproject.plugin.actionscript.as3parser.vo.ClassVO;
	import com.moonshineproject.text.change.TextChangeInsert;
	import com.moonshineproject.text.events.ChangeEvent;
	import com.moonshineproject.text.vo.CompletionContext;
	import com.moonshineproject.text.vo.CompletionResult;
	import com.moonshineproject.text.vo.ICompletionAction;
	
	import mx.collections.ArrayCollection;
	
	import org.as3commons.asblocks.parser.api.IParserNode;
	
	public class TypeCompleter extends BaseCompleter implements ICompletionAction
	{
		protected var metadata:MetadataManager;
		protected var importParser:ImportParser;
		
		public var completionContext:CompletionContext = new CompletionContext();
		
		
		public function TypeCompleter(meta:MetadataManager, importParser:ImportParser)
		{
			this.metadata = meta;
			this.importParser = importParser;
		}
		
		public function getCompletions(node:IParserNode, lastChar:String, caretIdx:int):ArrayCollection
		{
			var types:Vector.<ClassVO> = getTypeList();
			
			// Try to figure out where type declaration starts.
			// These cover cases for variables, functions, parameters to function & vectors
			//TODO: lastIndexOf(":") should work just as good & not look complicated?
			if (node.kind == "type" && lastChar == ":")
			{
				completionContext.filterCharStart = caretIdx;
			}
			else if (node.kind == "type")
			{
				completionContext.filterCharStart = node.column-1;
			}
			else if (node.kind == "name")
			{
				completionContext.filterCharStart = caretIdx;	
			}
			else if (node.kind == "parameter-list")
			{
				completionContext.filterCharStart = node.column+2;
			}
			else if (node.kind == "vector")
			{
				completionContext.filterCharStart = node.column + "Vector.<".length-1;
			}
			else if (node.kind == "new" && lastChar == " ")
			{
				completionContext.filterCharStart = caretIdx;
			}
			else if (node.kind == "primary" && node.parent.kind == "new")
			{
				completionContext.filterCharStart = node.parent.column + "new".length;
			}
			else if (node.kind == "extends" && lastChar == " ")
			{
				completionContext.filterCharStart = caretIdx;	
			}
			else if (node.kind == "implements" && lastChar == " ")
			{
				completionContext.filterCharStart = caretIdx;
			}
			
			var completions:ArrayCollection = new ArrayCollection();
			
			var type:ClassVO;
			for (var i:int = 0; i < types.length; i++)
			{
				type = types[i];
				var cr:CompletionResult = new CompletionResult();
				cr.completion = type.name;
				cr.label = type.name;
				cr.extra = type;
				completions.addItem(cr);
			}
			
			applySort(completions);
			
			completionContext.action = this;
			
			return completions;
		}
		
		public function apply(completion:CompletionResult):ChangeEvent
		{
			var pkgName:String = importParser.getPackageNameForType(completion.completion);
			if (!pkgName)
			{
				var position:int = importParser.lastImportLineIdx;
				if (position == -1) return null;
				
				var type:ClassVO = completion.extra;
				
				var name:String = type.getFullyQualifiedName();
				// If type is top-level we don't need to import
				if (name.indexOf(".") == -1) return null;
				
				// Add import statement for type
				var importString:String = "\timport " + name + ";";
				
				// Craft editor change event & return it
				// Add extra empty line to get a \n after it
				var lines:Vector.<String> = Vector.<String>([importString, ""]);
				var insert:TextChangeInsert = new TextChangeInsert(position, 0, lines);
				return new ChangeEvent(ChangeEvent.TEXT_CHANGE, insert);
			}
			
			return null;
		}
		
		protected function getTypeList():Vector.<ClassVO>
		{
			return metadata.globalPackageCache.getTypes(true);
		}

	}
}